import win32gui
import win32api
import win32process
import ctypes
import win32security
import win32con
import ctypes.wintypes
import time
from ctypes import *

Psapi = ctypes.WinDLL('Psapi.dll')
Kernel32 = ctypes.WinDLL('kernel32.dll')
PROCESS_QUERY_INFORMATION = 0x0400
PROCESS_VM_READ = 0x0010


def get_extra_privs():  # get more access to the game
    # Try to give ourselves some extra privs (only works if we're admin):
    # SeBackupPrivilege   - so we can read anything
    # SeDebugPrivilege    - so we can find out about other processes (otherwise OpenProcess will fail for some)
    # SeSecurityPrivilege - ??? what does this do?

    th = win32security.OpenProcessToken(win32api.GetCurrentProcess(),
                                        win32con.TOKEN_ADJUST_PRIVILEGES | win32con.TOKEN_QUERY)
    privs = win32security.GetTokenInformation(th, win32security.TokenPrivileges)
    newprivs = []
    for privtuple in privs:
        if privtuple[0] == win32security.LookupPrivilegeValue(None, "SeBackupPrivilege") or privtuple[
            0] == win32security.LookupPrivilegeValue(None, "SeDebugPrivilege") or privtuple[
            0] == win32security.LookupPrivilegeValue(None, "SeSecurityPrivilege"):
            # print("Added privilege " + str(privtuple[0]))
            newprivs.append((privtuple[0], 2))  # SE_PRIVILEGE_ENABLED
        else:
            newprivs.append((privtuple[0], privtuple[1]))

    # Adjust privs
    privs = tuple(newprivs)
    win32security.AdjustTokenPrivileges(th, False, privs)

def byte2Float(s):  # Convert byte to float
    try:
        i = int(s, 10)  # convert from Dec to a Python int
        cp = pointer(c_int(i))  # make this into a c integer
        fp = cast(cp, POINTER(c_float))  # cast the int pointer to a float pointer
        a = fp.contents.value
    except:
        a = 0
    finally:
        return a

def EnumProcessModulesEx(hProcess):
    buf_count = 256
    while True:
        LIST_MODULES_ALL = 0x03
        buf = (ctypes.wintypes.HMODULE * buf_count)()
        buf_size = ctypes.sizeof(buf)
        needed = ctypes.wintypes.DWORD()
        if not Psapi.EnumProcessModulesEx(hProcess, ctypes.byref(buf), buf_size, ctypes.byref(needed),
                                          LIST_MODULES_ALL):
            raise OSError('EnumProcessModulesEx failed')
        if buf_size < needed.value:
            buf_count = needed.value // (buf_size // buf_count)
            continue
        count = needed.value // (buf_size // buf_count)
        return map(ctypes.wintypes.HMODULE, buf[:count])


class Hp_getter():
    def __init__(self):
        get_extra_privs()
        print('============Gained Access to Memory=========')
        hd = win32gui.FindWindow(None, "StreetFighterV")
        pid = win32process.GetWindowThreadProcessId(hd)[1]
        self.process_handle = win32api.OpenProcess(0x1F0FFF, False, pid)
        self.kernal32 = ctypes.windll.LoadLibrary(r"C:\\Windows\\System32\\kernel32.dll")

        self.hx = 0
        # get dll address
        hProcess = Kernel32.OpenProcess(
            PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
            False, pid)
        hModule = EnumProcessModulesEx(hProcess)
        for i in hModule:
            temp = win32process.GetModuleFileNameEx(self.process_handle, i.value)
            if temp[-18:] == "StreetFighterV.exe":
                self.StreetFighter=i.value
                #print(self.StreetFighter)


    def get_self_HP_addr(self):
        base_address = self.StreetFighter + 0x03846378
        offset_address = base_address

        temp = ctypes.c_long()
        offset_list = [0x0, 0x0, 0xA0, 0x18, 0x48, 0x2F0, 0x618, 0x11C]
        for i in range(len(offset_list)-1):
            self.kernal32.ReadProcessMemory(int(self.process_handle), ctypes.c_void_p(offset_address + offset_list[i]),
                                            ctypes.byref(temp), 4, None)
            offset_address = temp.value & 0x00000000FFFFFFFF
        return offset_address + offset_list[-1]

    def get_rival_HP_addr(self):
        base_address = self.StreetFighter + 0x03846378
        offset_address = base_address
        temp = ctypes.c_long()
        offset_list = [0x0, 0x0, 0xA0, 0x18, 0x48, 0x90, 0x278, 0x11C]
        for i in range(len(offset_list) - 1):
            self.kernal32.ReadProcessMemory(int(self.process_handle), ctypes.c_void_p(offset_address + offset_list[i]),
                                            ctypes.byref(temp), 4, None)
            offset_address = temp.value & 0x00000000FFFFFFFF
        return offset_address + offset_list[-1]

    def get_self_addr(self):
        base_address = self.StreetFighter + 0x0382AE68
        offset_address = base_address
        temp_L = ctypes.c_long()
        temp_H = ctypes.c_long()
        offset_list = [0x0, 0x20, 0xf0, 0x50, 0x108, 0x118, 0x78, 0xc0]
        for i in range(len(offset_list) - 1):
            self.kernal32.ReadProcessMemory(int(self.process_handle), ctypes.c_void_p(offset_address + offset_list[i]),
                                            ctypes.byref(temp_L), 4, None)
            self.kernal32.ReadProcessMemory(int(self.process_handle),
                                            ctypes.c_void_p(offset_address + 4 + offset_list[i]),
                                            ctypes.byref(temp_H), 4, None)
            offset_address = temp_H.value * 4294967296 + ((
                                                                  temp_L.value + temp_H.value * 4294967296) & 0x0000FFFFFFFF)  # 4294967296是16^8次方，这里是做一个位移的操作 有符号数的十六进制是挺麻烦的
        self.kernal32.ReadProcessMemory(int(self.process_handle), ctypes.c_void_p(offset_address + offset_list[-1]),
                                        ctypes.byref(temp_L), 4, None)
        return offset_address + offset_list[-1]

    def get_rival_addr(self):
        base_address = self.StreetFighter + 0x03B04238
        offset_address = base_address
        temp_L = ctypes.c_long()
        temp_H = ctypes.c_long()
        offset_list = [0x0, 0x190, 0x308, 0x368, 0x20, 0x2b8, 0x78, 0xc0]
        for i in range(len(offset_list) - 1):
            self.kernal32.ReadProcessMemory(int(self.process_handle), ctypes.c_void_p(offset_address + offset_list[i]),
                                            ctypes.byref(temp_L), 4, None)
            self.kernal32.ReadProcessMemory(int(self.process_handle),
                                            ctypes.c_void_p(offset_address + 4 + offset_list[i]),
                                            ctypes.byref(temp_H), 4, None)
            offset_address = temp_H.value * 4294967296 + ((
                                                                  temp_L.value + temp_H.value * 4294967296) & 0x0000FFFFFFFF)  # 4294967296是16^8次方，这里是做一个位移的操作 有符号数的十六进制是挺麻烦的
        self.kernal32.ReadProcessMemory(int(self.process_handle), ctypes.c_void_p(offset_address + offset_list[-1]),
                                        ctypes.byref(temp_L), 4, None)
        # print(int(convert(str(temp_L.value))))
        return offset_address + offset_list[-1]

    def get_value(self, address):

        return_value = ctypes.c_void_p()
        self.kernal32.ReadProcessMemory(int(self.process_handle), ctypes.c_void_p(address),
                                        ctypes.byref(return_value), 4, None)
        if return_value.value is None:
            return 0
        else:
            return return_value.value

    def direction(self,playerx,rivalx):
        if playerx-rivalx<0:
            return "Left"    #player on left
        else:
            return "Right"    #player of right

if __name__ == "__main__":
    #get_extra_privs()
    hp = Hp_getter()
    seloc = hp.get_self_addr()
    rivloc = hp.get_rival_addr()
    selfhpaddr = hp.get_self_HP_addr()
    rivalhpaddr = hp.get_rival_HP_addr()
    while True:
        playerx = int(byte2Float(str(hp.get_value(seloc))))
        rivalx = int(byte2Float(str(hp.get_value(rivloc))))
        selfHP = hp.get_value(selfhpaddr)
        rivalHP = hp.get_value(rivalhpaddr)
        print(rivalx,playerx,selfHP,rivalHP,hp.direction(playerx,rivalx))




